package cn.xyz.mianshi.service.impl;

import cn.xyz.commons.constants.KConstants;
import cn.xyz.commons.constants.KConstants.*;
import cn.xyz.commons.ex.ServiceException;
import cn.xyz.commons.support.mongo.MongoOperator;
import cn.xyz.commons.utils.DateUtil;
import cn.xyz.commons.utils.HttpClientUtil;
import cn.xyz.commons.utils.StringUtil;
import cn.xyz.commons.vo.JSONMessage;
import cn.xyz.mianshi.model.PageResult;
import cn.xyz.mianshi.opensdk.entity.SkOpenApp;
import cn.xyz.mianshi.service.PayService;
import cn.xyz.mianshi.utils.SKBeanUtils;
import cn.xyz.mianshi.vo.Bank;
import cn.xyz.mianshi.vo.CodePay;
import cn.xyz.mianshi.vo.ConsumeRecord;
import cn.xyz.mianshi.vo.PayChannel;
import cn.xyz.mianshi.vo.PayInfo;
import cn.xyz.mianshi.vo.PayOrder;
import cn.xyz.mianshi.vo.PayScoreInfo;
import cn.xyz.mianshi.vo.User;
import cn.xyz.repository.mongo.MongoRepository;
import cn.xyz.service.AuthServiceOldUtils;
import cn.xyz.service.KXMPPServiceImpl;
import cn.xyz.service.KXMPPServiceImpl.MessageBean;
import cn.xyz.service.RedisServiceImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.AggregationOutput;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.shiku.commons.task.TimerTask;
import com.shiku.commons.thread.Callback;
import com.shiku.commons.thread.ThreadUtils;
import com.shiku.utils.Base64;
import com.wxpay.utils.MD5Util;
import com.wxpay.utils.WXPayUtil;
import com.wxpay.utils.http.HttpClientConnectionManager;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.query.Query;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.net.UnknownHostException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import javax.crypto.Cipher;
import javax.servlet.http.HttpServletResponse;
@Service
public class PayServiceImpl extends MongoRepository<CodePay,ObjectId> implements PayService {
	
	public static DefaultHttpClient httpclient = new DefaultHttpClient(new ThreadSafeClientConnManager());
	
	@Override
	public Datastore getDatastore() {
		// TODO Auto-generated method stub
		return SKBeanUtils.getDatastore();
	}

	@Override
	public Class<CodePay> getEntityClass() {
		// TODO Auto-generated method stub
		return CodePay.class;
	}
	
	@SuppressWarnings("unused")
	private static RedisServiceImpl getRedisServiceImpl(){
		return SKBeanUtils.getRedisService();
	}
	
	/**
	 * 解析20位支付码
	 * 加密规则   (userId+n+opt)长度+(userId+n+opt)+opt+(time/opt)
	 * @param paymentCode
	 * @return
	 */
	public Integer analysisCode(String paymentCode){
		int n=9;// 固定值
		String userIdCodeLength=paymentCode.substring(0, 1);// 第一位数（userId+n+opt）的长度
		
		// userIdCode=userId+n+opt
		String userIdCode=paymentCode.substring(userIdCodeLength.length(),Integer.valueOf(userIdCodeLength)+1);
		
		int three=userIdCodeLength.length()+userIdCode.length();
		String opt=paymentCode.substring(three, three+3);
		
		int four=three+3;
		// timeCode=time/opt
		String timeCode=paymentCode.substring(four,paymentCode.length());
		
		int userId=Integer.valueOf(userIdCode)-n-Integer.valueOf(opt);
		
		long time=Integer.valueOf(timeCode)*Integer.valueOf(opt);
		if(System.currentTimeMillis()/1000-time<256){
			return userId;
		}else{
			time=Integer.valueOf(timeCode)*(Integer.valueOf(opt)-100);
			if(System.currentTimeMillis()/1000-time<256){
				return userId;
			}else{
				return null;
			}
		}
		
	}
	
	/**
	 * 付款码操作账户金额
	 * @param userId 收线方
	 * @param fromUserId 付款方--码的所有方
	 * @param money
	 */
	public synchronized void paymentCodePay(String paymentCode,Integer userId,Integer fromUserId,String money,String desc){
		User fromUser=SKBeanUtils.getUserManager().get(fromUserId);
		User user=SKBeanUtils.getUserManager().get(userId);
		Double balance = SKBeanUtils.getUserManager().getUserMoenyV1(fromUserId);
		Double doubleMoney = Double.valueOf(money);
		if(doubleMoney < 0)
		{
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		if(balance<doubleMoney){
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		if(doubleMoney>50){
			throw new ServiceException("最多支持 50元支付!");
		}else if(balance< doubleMoney){
			throw new ServiceException("对方余额不足,扣款失败");
		}
		double toDayCodePayCount = queryToDayCodePayCount(fromUserId);
		if((toDayCodePayCount+doubleMoney)>500){
			throw new ServiceException("当天付款已超限额,扣款失败");
		}
		double count = queryCodePayCount(fromUserId);
		if(count>5000){
            throw new ServiceException("总付款已超限额,扣款失败");
        }
        CodePay codePay=new CodePay();
		codePay.setUserId(fromUserId);
		codePay.setUserName(fromUser.getNickname());
		codePay.setType(1);
		codePay.setToUserId(userId);
		codePay.setToUserName(user.getNickname());
		codePay.setMoney(doubleMoney);
		codePay.setCreateTime(DateUtil.currentTimeSeconds());
			saveCodePay(codePay);
		// 减钱
		SKBeanUtils.getUserManager().rechargeUserMoeny(fromUserId, doubleMoney, KConstants.MOENY_REDUCE);
		String lessTradeNo=StringUtil.getOutTradeNo();
		//创建减钱消费记录
		ConsumeRecord lessRecord=new ConsumeRecord();
		lessRecord.setUserId(fromUserId);
		lessRecord.setToUserId(userId);
		lessRecord.setTradeNo(lessTradeNo);
		lessRecord.setMoney(doubleMoney);
		lessRecord.setStatus(KConstants.OrderStatus.END);
		lessRecord.setType(KConstants.ConsumeType.SEND_PAYMENTCODE);
		lessRecord.setPayType(KConstants.PayType.BALANCEAY); //余额支付
		if(!StringUtil.isEmpty(desc))
			lessRecord.setDesc(desc);
		else
			lessRecord.setDesc("付款码已付款");
		lessRecord.setTime(DateUtil.currentTimeSeconds());
		SKBeanUtils.getConsumeRecordManager().save(lessRecord);
		
		// 发送xmpp扣款消息通知
		User sysUser=SKBeanUtils.getUserManager().get(1100);
		MessageBean messageBean = new MessageBean();
		messageBean.setFromUserId(sysUser.getUserId().toString());
		messageBean.setFromUserName(sysUser.getNickname());
		messageBean.setType(KXMPPServiceImpl.CODEPAYMENT);
		messageBean.setContent(JSONObject.toJSONString(codePay));
		messageBean.setMsgType(0);// 普通单聊消息
		messageBean.setMessageId(StringUtil.randomUUID());
		messageBean.setToUserId(fromUserId.toString());
		messageBean.setToUserName(fromUser.getNickname());
		try {
			KXMPPServiceImpl.getInstance().send(messageBean);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 加钱
		SKBeanUtils.getUserManager().rechargeUserMoeny(userId, doubleMoney, KConstants.MOENY_ADD);
		String addTradeNo=StringUtil.getOutTradeNo();
		//创建加钱消费记录
		ConsumeRecord addRecord=new ConsumeRecord();
		addRecord.setUserId(userId);
		addRecord.setToUserId(fromUserId);
		addRecord.setTradeNo(addTradeNo);
		addRecord.setMoney(doubleMoney);
		addRecord.setStatus(KConstants.OrderStatus.END);
		addRecord.setType(KConstants.ConsumeType.RECEIVE_PAYMENTCODE);
		addRecord.setPayType(KConstants.PayType.BALANCEAY); //余额支付
		addRecord.setDesc("付款码已收款");
		addRecord.setTime(DateUtil.currentTimeSeconds());
		SKBeanUtils.getConsumeRecordManager().save(addRecord);
		
		// 发送xmpp通知收款成功
		MessageBean message=new MessageBean();
		message.setFromUserId(sysUser.getUserId().toString());
		message.setFileName(sysUser.getNickname());
		message.setType(KXMPPServiceImpl.CODEARRIVAL);
		message.setMsgType(0);
		message.setMessageId(StringUtil.randomUUID());
		message.setContent(JSONObject.toJSONString(codePay));
		message.setToUserId(userId.toString());
		message.setToUserName(user.getNickname());
		try {
			KXMPPServiceImpl.getInstance().send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 保存用户付款码缓存
		getRedisServiceImpl().savePaymentCode(paymentCode, fromUserId);
	}

	public String getPayQrKey(int userId){
		String qrKey = SKBeanUtils.getRedisService().queryPayQrKey(userId);
		if(!StringUtil.isEmpty(qrKey))
			return  qrKey;
		byte[] codeArr=new byte[16];
		Random rom =new Random();
		rom.nextBytes(codeArr);
		qrKey = Base64.encode(codeArr);
		SKBeanUtils.getRedisService().savePayQrKey(userId,qrKey);
		return qrKey;
	}

	/**
	 * 检验付款码唯一性
	 * @param userId
	 * @param paymentCode
	 * @return
	 */
	public boolean checkPaymentCode(Integer userId,String paymentCode){
		Integer value=getRedisServiceImpl().getPaymentCode(paymentCode);
		if(null!=value){
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * 二维码收钱操作金额
	 * @param userId  付款方(金额减少)
	 * @param fromUserId  收线方(金额增加)--码的所有者
	 * @param money
	 */
	public synchronized void receipt(Integer userId,Integer fromUserId,String money,String desc){
		User user = SKBeanUtils.getUserManager().get(userId);
		User fromUser = SKBeanUtils.getUserManager().get(fromUserId);
		Double balance = SKBeanUtils.getUserManager().getUserMoenyV1(userId);
		if(balance<Double.valueOf(money)){
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		if(Double.valueOf(money)<0){
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		CodePay codePay=new CodePay();
		codePay.setUserId(fromUserId);
		codePay.setType(2);
		codePay.setUserName(fromUser.getNickname());
		codePay.setToUserId(userId);
		codePay.setToUserName(user.getNickname());
		codePay.setMoney(Double.valueOf(money));
		codePay.setCreateTime(DateUtil.currentTimeSeconds());
		saveCodePay(codePay);
		
		SKBeanUtils.getUserManager().rechargeUserMoeny(userId, Double.valueOf(money), KConstants.MOENY_REDUCE);
		String lessTradeNo=StringUtil.getOutTradeNo();
		//创建减钱消费记录 
		ConsumeRecord lessRecord=new ConsumeRecord();
		lessRecord.setUserId(userId);
		lessRecord.setToUserId(fromUserId);
		lessRecord.setTradeNo(lessTradeNo);
		lessRecord.setMoney(Double.valueOf(money));
		lessRecord.setStatus(KConstants.OrderStatus.END);
		lessRecord.setType(KConstants.ConsumeType.SEND_QRCODE);
		lessRecord.setPayType(KConstants.PayType.BALANCEAY); // 余额支付
		if(!StringUtil.isEmpty(desc))
			lessRecord.setDesc(desc);
		else
			lessRecord.setDesc("二维码收款已付款");
		lessRecord.setTime(DateUtil.currentTimeSeconds());
		SKBeanUtils.getConsumeRecordManager().save(lessRecord);
		
		User sysUser=SKBeanUtils.getUserManager().get(1100);
		MessageBean messageBean = new MessageBean();
		messageBean.setFromUserId(sysUser.getUserId().toString());
		messageBean.setFromUserName(sysUser.getNickname());
		messageBean.setType(KXMPPServiceImpl.CODERECEIPT);
		messageBean.setContent(JSONObject.toJSONString(codePay));
		messageBean.setMsgType(0);// 普通单聊消息
		messageBean.setMessageId(StringUtil.randomUUID());
		messageBean.setToUserId(user.getUserId().toString());
		messageBean.setToUserName(user.getNickname());
		try {
			KXMPPServiceImpl.getInstance().send(messageBean);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 加钱
		SKBeanUtils.getUserManager().rechargeUserMoeny(fromUserId, Double.valueOf(money), KConstants.MOENY_ADD);
		String addTradeNo=StringUtil.getOutTradeNo();
		// 创建加钱消费记录
		ConsumeRecord addRecord=new ConsumeRecord();
		addRecord.setUserId(fromUserId);
		addRecord.setToUserId(userId);
		addRecord.setTradeNo(addTradeNo);
		addRecord.setMoney(Double.valueOf(money));
		addRecord.setStatus(KConstants.OrderStatus.END);
		addRecord.setType(KConstants.ConsumeType.RECEIVE_QRCODE);
		addRecord.setPayType(KConstants.PayType.BALANCEAY); //余额支付
		addRecord.setDesc("二维码收款已到账");
		addRecord.setTime(DateUtil.currentTimeSeconds());
		SKBeanUtils.getConsumeRecordManager().save(addRecord);

			// 发送xmpp通知收款成功
			MessageBean message=new MessageBean();
			message.setFromUserId(sysUser.getUserId().toString());
			message.setFromUserName(sysUser.getNickname());
			message.setType(KXMPPServiceImpl.CODEERECEIPTARRIVAL);
			message.setMsgType(0);
			message.setMessageId(StringUtil.randomUUID());
			message.setContent(JSONObject.toJSON(codePay));
			message.setToUserId(fromUser.getUserId().toString());
			message.setToUserName(fromUser.getNickname());
			try {
				KXMPPServiceImpl.getInstance().send(message);
			} catch (Exception e) {
				e.printStackTrace();
			}
	}
	
	public void saveCodePay(CodePay entity){
		save(entity);
		
	}
	
	/**
	 * 统一下单接口
	 * @return
	 * @throws Exception
	 */
	public JSONMessage unifiedOrderImpl(Map<String, String> map) throws Exception{
		// 验签
		if(!checkSign(map.get("appId"), map.get("body"), map.get("input_charset"), map.get("nonce_str"), map.get("out_trade_no"), map.get("total_fee"), map.get("trade_type"),map.get("notify_url"),map.get("spbill_create_ip"), map.get("sign"))){
			return JSONMessage.failureByErrCode(PayResultCode.AuthSignFailed);
		}
		
		// 判断app是否存在第三方平台
		if(map.get("trade_type").equals("APP")){
			SkOpenApp openApp = SKBeanUtils.getOpenAppManage().getOpenAppByAppId(map.get("appId"));
			if(null==openApp){
				return JSONMessage.failureByErrCode(PayResultCode.NotWithThirdParty);
			}else if(openApp.getIsAuthPay()!=1){
				// 支付权限不足
				return JSONMessage.failureByErrCode(KConstants.ResultCode.NO_PERMISSION);
			}
		}else if(map.get("trade_type").equals("WEB")){
			SkOpenApp openWeb=SKBeanUtils.getOpenWebAppManage().checkWebAPPByAppId(map.get("appId"));
			if(null==openWeb){
				return JSONMessage.failureByErrCode(PayResultCode.NotWithThirdParty);
			}else if(openWeb.getIsAuthPay()!=1){
				// 支付权限不足
				return JSONMessage.failureByErrCode(KConstants.ResultCode.NO_PERMISSION);
			}
		}
		
		// 生成订单
		PayOrder payOrder = new PayOrder();
		payOrder.setAppId(map.get("appId"));
		payOrder.setMoney(map.get("total_fee"));
		payOrder.setTrade_no(map.get("trade_no"));
		payOrder.setCreateTime(DateUtil.currentTimeSeconds());
		payOrder.setIPAdress(map.get("spbill_create_ip"));
		payOrder.setDesc(map.get("body"));
		payOrder.setAppType(map.get("trade_type"));
		payOrder.setCallBackUrl(map.get("notify_url"));
		payOrder.setStatus((byte)0);
		payOrder.setSign(map.get("sign"));
		payOrder.setId(ObjectId.get());
		saveEntity(payOrder);
		
		SKBeanUtils.getRedisService().savePayOrderSign(payOrder.getId().toString(), map.get("sign"));
		
		SortedMap<String, String> contentMap = new TreeMap<String, String>();
		contentMap.put("prepay_id", payOrder.getId().toString());
		String resultxml = WXPayUtil.paramsToxmlStr(contentMap);
		return JSONMessage.success(resultxml);
	}


	public  JSONMessage unifiedOrderExImpl(Map<String, String> map)
	{
		if(!checkSign(map.get("appId"),map.get("body"),"", map.get("nonce_str"), map.get("trade_no"), map.get("total_fee"), map.get("trade_type"),map.get("notify_url"),"", map.get("sign"))){
			return JSONMessage.failureByErrCode(PayResultCode.AuthSignFailed);
		}
		//检查订单号是否已经存在
		String szOrderId = map.get("appId") +  map.get("trade_no");
		String szOrder = SKBeanUtils.getRedisService().queryUserPayOrderSign(szOrderId);
		if(szOrder != null)
		{
			return JSONMessage.failureByErrCode(PayResultCode.OrderNotExist);
		}
		//订单入库
		PayOrder payOrder = new PayOrder();
		payOrder.setAppId(map.get("appId"));
		payOrder.setMoney(map.get("total_fee"));
		payOrder.setTrade_no(map.get("trade_no"));
		payOrder.setCreateTime(DateUtil.currentTimeSeconds());
		payOrder.setIPAdress("");
		payOrder.setDesc(map.get("body"));
		payOrder.setAppType("APP");
		payOrder.setCallBackUrl(map.get("notify_url"));
		payOrder.setStatus((byte)0);
		payOrder.setSign(map.get("sign"));
		payOrder.setId(ObjectId.get());
		saveEntity(payOrder);

		SKBeanUtils.getRedisService().saveUserPayOrderSign(map.get("appId") + map.get("trade_no"), map.get("sign"));
		SKBeanUtils.getRedisService().savePayOrderSign( payOrder.getId().toString(), map.get("sign"));
		SortedMap<String, String> contentMap = new TreeMap<String, String>();
		contentMap.put("appId",map.get("appId"));
		contentMap.put("prepayId", payOrder.getId().toString());
		contentMap.put("sign",map.get("sign"));
		return JSONMessage.success(contentMap);
	}
	public PayInfo getPayInfo()
	{
		PayInfo _return =new PayInfo();
			Query<PayScoreInfo> query = getDatastore().createQuery(PayScoreInfo.class).filter("PayChannel", 0)
				 .filter("Status", 0);
			List<PayScoreInfo> recordList = query.asList(pageFindOption(1,100,1));
			_return.setData(recordList);
			
			Query<PayChannel> queryChannel = getDatastore().createQuery(PayChannel.class);
			PayChannel channel =  queryChannel.get();
			_return.setIsOpenAlipay(channel.getIsOpenAlipay());
			_return.setIsOpenBank(channel.getIsOpenBank());
			_return.setIsOpenWechat(channel.getIsOpenWechat());
			return _return;
	}
	//修改支付通道
	public void SavePayInfo(String id,int isOpenAlipay,int isOpenBank,int isOpenWechat)
	{
		PayChannel _data = new PayChannel();
		_data.setIsOpenAlipay(isOpenAlipay);
		_data.setIsOpenBank(isOpenBank);
		_data.setIsOpenWechat(isOpenWechat);
		if(id.equals("0"))
		{
			saveEntity(_data);
		}
		else {
			updateEntity(PayChannel.class,new ObjectId(id),_data);
		}
	}
	public void SavePayScore(String id,int PricValue,int Status,int PayChannel)
	{
		PayScoreInfo _data = new PayScoreInfo();
		_data.setPayChannel(PayChannel);
		_data.setPricValue(PricValue);
		_data.setStatus(Status);
		if(id.equals("0"))
		{
			saveEntity(_data);
		}
		else {
			_data.setId(new ObjectId(id));
			updateEntity(PayScoreInfo.class,new ObjectId(id),_data);
		}
	}
	public JSONMessage  paySdkOrderImpl(Integer userId,String payType,Double amount,String requestIp, HttpServletResponse response)
	{
		String out_trade_no =StringUtil.getOutTradeNo();
		//return  PayForPgPay(userId,payType,amount,out_trade_no,requestIp,response);
		return  PayForYiLe(userId,payType,amount,out_trade_no,requestIp,response);
	}
	//亿乐支付
	public JSONMessage PayForYiLe(Integer userId,String payType,Double amount,String out_trade_no,String requestIp, HttpServletResponse response)
	{
		DecimalFormat decimalFormat=new DecimalFormat(".00");//构造方法的字符格式这里如果小数不足2位,会以0补足.
		String  szAmount= decimalFormat.format(amount);//format 返回的是字符串
		
		SortedMap<String, String> contentMap = new TreeMap<String, String>();
		contentMap.put("appid", SKBeanUtils.getPayConfig().getYlAppID());
		contentMap.put("pay_type", payType);
		contentMap.put("amount", szAmount);
		contentMap.put("callback_url", SKBeanUtils.getPayConfig().getYlCallback());
		contentMap.put("success_url", SKBeanUtils.getPayConfig().getYlSccuessback());
		contentMap.put("error_url",SKBeanUtils.getPayConfig().getYlErrback());
		contentMap.put("out_uid", userId+"");
		contentMap.put("out_trade_no", out_trade_no);
		contentMap.put("version", "v1.1");
		String params= createSignParam(contentMap)+"key="+SKBeanUtils.getPayConfig().getYlSecretKey();
		logger.info("[ww]:pay params="+params);
		String sign = MD5Util.MD5Encode(params, "UTF-8").toUpperCase();
		logger.info("[ww]:pay sign="+sign);
		contentMap.put("sign", sign);
		
		
		
	
		//创建充值记录
		ConsumeRecord record=new ConsumeRecord();
		record.setUserId(userId);
	
		record.setTradeNo(contentMap.get("out_trade_no"));
		record.setMoney( amount);
		record.setStatus(KConstants.OrderStatus.CREATE);
		record.setType(KConstants.ConsumeType.USER_RECHARGE);
		record.setPayType(KConstants.PayType.BALANCEAY); //余额支付
		record.setDesc("用户充值");
		record.setTime(DateUtil.currentTimeSeconds());
		//record.setOperationAmount(amount);
		//record.setCurrentBalance(balance);
		SKBeanUtils.getConsumeRecordManager().save(record);
		
		try {
			String resultValue  = HttpClientUtil.sendGetMessage(SKBeanUtils.getPayConfig().getYlUrl(),contentMap,"POST");
			logger.info("[ww]:pay=result="+resultValue);
			if(resultValue.indexOf("http")>=0)
			{
				response.setStatus(302);
				response.setHeader("location", resultValue);
				return JSONMessage.success();
			}
			JSONObject _jsonReturn = JSONObject.parseObject(resultValue);
			return JSONMessage.success(_jsonReturn); 
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.info("[ww]:pay=err="+e.toString());
			e.printStackTrace();
		}
		logger.info("[ww]:pay=end");
		return JSONMessage.success();
	}
	//印尼pg支付
	public JSONMessage PayForPgPay(Integer userId,String payType,Double amount,String out_trade_no,String requestIp, HttpServletResponse response)
	{
		   logger.info("[ww]:PayForPgPay");
		LocalDateTime date = LocalDateTime.now();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
		String  szAmount= amount.longValue()+"";
		
		String MCH_PRIVATE_KEY = SKBeanUtils.getpgPayConfig().getPgPrivateKey();
		String merchantCode = SKBeanUtils.getpgPayConfig().getMerchantCode();
		String method = SKBeanUtils.getpgPayConfig().getMethod();
		String notifyUrl = SKBeanUtils.getpgPayConfig().getPgCallback();
		String tagUrl =SKBeanUtils.getpgPayConfig().getPgTagUrl();
		//String PLAT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLmhPPvLCjHwFl2l1gg/UtdvyqpbuDvqHL5Z+UwjIaz3MaDWkkPtPLM6XleXhliJOCiMXrjUSjmxati+cHke3m9uXc3mpwXeHwxHNwxWHR9Y9OEgWX2b6iwVd8IU0O71G53pYsXZLYQ+sFxirzHqqpLzik1sdeGmLyhK5uhn67DwIDAQAB";
		//String MCH_PRIVATE_KEY ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMRx/tJBb9ej3Myy3Rpv51suFLHNUO+L6zlUR7RDAHEAg/UNbKvZA4qwPKEnZxaq19z0VOwtepVwW6fZDC2CLrZpa9FgqPkbOsGw9iLXrLpmmIG6mgOWUukcyXBtre3AHkdCmrqXqCZl0LkxtHk1At32RgJiwRqvc+CXHGmqbkLLAgMBAAECgYBSdd+XdqxyAnDO5E33qP2ewqshL6RHyZ4FxKEMxAtNZAAAP5BcWo4oC26H3zhgxXozX8S+FyEb1bxDqtJ3z+u3HYJKKciNjqospI6psu8BhbrSIwKqcOHx8sdp8mgGKOyeftKB8gUTKRam2KV0H8ec/PMei4yA2N77MtACa3tXMQJBAPOpKBvO4VXJghrm6Fb/iFVixqyCUXFf3fAYM17qJvj/eas/aWhHMvzE1MIn5zOwu+DaNBOxtALnDZxopX8zHG0CQQDOZLuB6MiMvGOcblldNxoWwL2WeDN/c/6RYtJlt7FBEtwmiyjxOcgLUjT0iyFNM7cGjLJsNujPlBA2eIiGJmkXAkEA8uYKac5Oq+p5nL/blf6etiAF1isDbXYYFSTK8S+TMl3buG86cQ2pMno1bmfA/7KLWJetmoRn4wzacLWRZcBZ8QJAYBGBOenJl8CEuSagEAR670ZNuQFALz4lqzSNbG1BY2HM+V/i8c2McMCWB5HPMWk18yWAU2CHoz9vAHvASHkOhwJAWgjexwwxZAPRmeqaTAeWdesOc0jjGcvHQQJeh+NFI6WUylsgeV7Fhz8ml8yKcz2S9pHnLSVy29ytprdt3+IUDQ==";
		
		String _szName="";
		for(int i=0;i<10;i++)
		{
			char c = (char)((Math.random()*26)+97);
			_szName += (c +"");
		}
		
		Map<String, String> contentMap = new HashMap<>();
		//contentMap.put("merchantCode", "S820201013115254000009");
		//contentMap.put("method", "M1");
		contentMap.put("notifyUrl", notifyUrl);
		contentMap.put("merchantCode", merchantCode);
		contentMap.put("method", method);
		contentMap.put("orderNum", out_trade_no);
		contentMap.put("payMoney", szAmount);
		contentMap.put("productDetail", "Kitegram Pay");
		contentMap.put("name",_szName);
		contentMap.put("email", "pay@Kitegram.com");
		contentMap.put("notifyUrl", notifyUrl);
		contentMap.put("dateTime", date.format(formatter));
		contentMap.put("phone", "082112345678");
		contentMap.put("expiryPeriod", "4320");
		
	      List<String> paramNameList = new ArrayList<>();
	        for (String key : contentMap.keySet()) {
	            paramNameList.add(key);
	        }
	        Collections.sort(paramNameList);  // 排序key
	        StringBuilder stringBuilder = new StringBuilder();
	        for (int i = 0; i < paramNameList.size(); i++) {
	            String key = paramNameList.get(i);
	            stringBuilder.append(contentMap.get(key));  // 拼接参数
	        }
	        String keyStr = stringBuilder.toString();  // 得到待加密的字符串
	        String signedStr = "";
	        try {
	            signedStr = privateEncrypt(keyStr, getPrivateKey(MCH_PRIVATE_KEY));  // 私钥加密
	            
	        } catch (Exception e) {
	            System.out.println(e);
	        }
	        contentMap.put("sign", signedStr);
	        String postStr = JSON.toJSONString(contentMap);
	      
	        JSONObject postJson = JSONObject.parseObject(postStr);
	       // JSONObject returnObj = HttpClientUtil.SendMsgToPgpay("https://openapi.pgpay.cc/gateway/prepaidOrder", postJson);
	        JSONObject returnObj = HttpClientUtil.SendMsgToPgpay(tagUrl, postJson);
	        logger.info("[ww]:PayForPgPay="+JSON.toJSONString(returnObj));
	        return JSONMessage.success(returnObj); 
	        //return JSONMessage.success();
	}
	
	public  boolean verifySign(JSONObject params) {
		String PLAT_PUBLIC_KEY =  SKBeanUtils.getpgPayConfig().getPgPublicKey();
        String platSign = params.getString("platSign"); // 签名
        
        List<String> paramNameList = new ArrayList<>();
        for (String key : params.keySet()) {
            if (!"platSign".equals(key)) {
                paramNameList.add(key);
            }
        }
        Collections.sort(paramNameList);
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < paramNameList.size(); i++) {
            String name = paramNameList.get(i);
            stringBuilder.append(params.getString(name));
        }
        
        String decryptSign = "";
        try {
            decryptSign = publicDecrypt(platSign, getPublicKey(PLAT_PUBLIC_KEY));
        } catch (Exception e){
            System.out.println(e.toString());
        }
        //System.out.println("decryptSign:" + decryptSign);

        if (!stringBuilder.toString().equalsIgnoreCase(decryptSign)) {
            return false;
        }
        return true;
    }

	   public static String privateEncrypt(String data, RSAPrivateKey privateKey){
	        try{
	            Cipher cipher = Cipher.getInstance("RSA");
	            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
	            return Base64.encode(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), privateKey.getModulus().bitLength()));
	        }catch(Exception e){
	            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
	        }
	    }
	   
	 public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
	        //通过PKCS#8编码的Key指令获得私钥对象
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	    
	        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
	        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
	        return key;
	    }
	 public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
	        //通过X509编码的Key指令获得公钥对象
	        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
	        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decode(publicKey));
	        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
	        return key;
	    }
	 public static String publicDecrypt(String data, RSAPublicKey publicKey){
	        try{
	            Cipher cipher = Cipher.getInstance("RSA");
	            cipher.init(Cipher.DECRYPT_MODE, publicKey);
	            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decode(data), publicKey.getModulus().bitLength()), "UTF-8");
	        }catch(Exception e){
	            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
	        }
	 }
	 
	 private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
	        int maxBlock = 0;
	        if(opmode == Cipher.DECRYPT_MODE){
	            maxBlock = keySize / 8;
	        }else{
	            maxBlock = keySize / 8 - 11;
	        }
	        ByteArrayOutputStream out = new ByteArrayOutputStream();
	        int offSet = 0;
	        byte[] buff;
	        int i = 0;
	        try{
	            while(datas.length > offSet){
	                if(datas.length-offSet > maxBlock){
	                    buff = cipher.doFinal(datas, offSet, maxBlock);
	                }else{
	                    buff = cipher.doFinal(datas, offSet, datas.length-offSet);
	                }
	                out.write(buff, 0, buff.length);
	                i++;
	                offSet = i * maxBlock;
	            }
	        }catch(Exception e){
	            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
	        }
	        byte[] resultDatas = out.toByteArray();
	        IOUtils.closeQuietly(out);
	        return resultDatas;
	    } 
	 
	public void AddMoeny(String tradeNo)
	{
		ConsumeRecord entity = SKBeanUtils.getConsumeRecordManager().getConsumeRecordByNo(tradeNo);
		if(entity.getStatus() != KConstants.OrderStatus.CREATE) return;
		Double balance = SKBeanUtils.getUserManager().rechargeUserMoeny(entity.getUserId(), entity.getMoney(), KConstants.MOENY_ADD);
		entity.setStatus(KConstants.OrderStatus.END);
		entity.setOperationAmount(entity.getMoney());
		entity.setCurrentBalance(balance);
		SKBeanUtils.getConsumeRecordManager().update(entity.getId(), entity);
		logger.info("支付成功 {}",tradeNo);
		
	}
	
	public String createSignParam(SortedMap<String, String> packageParams) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)) {
				sb.append(k + "=" + v + "&");
				//System.out.println(k+"----"+v);
			}
		}
		return sb.toString();
	}
	public boolean checkSignV1(SortedMap<String, String> packageParams,String  sign)
	{
		 String params =  createSignParam(packageParams)+"key="+SKBeanUtils.getPayConfig().getYlSecretKey();
		 String sign_1 = MD5Util.MD5Encode(params, "UTF-8").toUpperCase();
		 String sign_2 = sign.toUpperCase();
		 return sign_1.equals(sign_2);
	}
	/**
	 * 校验签名
	 * @param appId 
	 * @param body 商品描述
	 * @param input_charset 字符编码
	 * @param nonce_str 随机字符
	 * @param trade_no 订单编号
	 * @param total_fee 金额
	 * @param trade_type 支付应用类型
	 * @param sign 签名
	 * @return
	 */
	public boolean checkSign(String appId,String body,String input_charset,String nonce_str,String trade_no,
		String total_fee,String trade_type,String notify_url,String spbill_create_ip,String sign){
		SortedMap<String, String> contentMap = new TreeMap<String, String>();
		contentMap.put("appId", appId);
		contentMap.put("body", body);
		contentMap.put("input_charset", input_charset);
		contentMap.put("nonce_str", nonce_str);
		contentMap.put("notify_url", notify_url);
		contentMap.put("spbill_create_ip", spbill_create_ip);
		contentMap.put("total_fee", total_fee);
		contentMap.put("trade_no", trade_no);
		contentMap.put("trade_type", trade_type);


		String szSecretKey ="123456";

		String signKey=createSign(contentMap,szSecretKey);
		
		if(signKey.equals(sign)){
			return true;
		}else{
			return false;
		}
		
	}
	
	/**
	 * 获取预支付订单信息

	 * @param prepayId
	 * @return
	 */
	public JSONMessage getOrderInfo(String prepayId){
		Query<PayOrder> query = getDatastore().createQuery(PayOrder.class).field("_id").equal(new ObjectId(prepayId));

		PayOrder payOrder = query.get();
		Map<String,String> map = new HashMap<>();
		map.put("money", payOrder.getMoney());
		map.put("desc", payOrder.getDesc());
		return JSONMessage.success(null, map);
	}
	
	/**
	 * 确认密码支付
	 * @param appId
	 * @param prepayId
	 * @param sign
	 * @param userId
	 * @return
	 */
	public JSONMessage passwordPayment(String appId,String prepayId,String sign,Integer userId,String token,long time,String secret,String salt){
		
		User user = SKBeanUtils.getUserManager().get(userId);

		if(StringUtil.isEmpty(salt)){
			if(!AuthServiceOldUtils.authPaymentSecret(userId.toString(), token, user.getPayPassword(), time, secret)){
				return JSONMessage.failureByErrCode(KConstants.ResultCode.AUTH_FAILED);
			}
		}


		if(!SKBeanUtils.getRedisService().queryPayOrderSign(prepayId).equals(sign)){
			return JSONMessage.failureByErrCode(PayResultCode.AuthSignFailed);
		}
		
		Query<PayOrder> query = getDatastore().createQuery(PayOrder.class).field("_id").equal(new ObjectId(prepayId));
		if(null==query.get()){
			return JSONMessage.failureByErrCode(PayResultCode.OrderNotExist);
		}
		
		PayOrder order = query.get();

		if(Double.valueOf(order.getMoney())<0){
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		if(!order.getAppId().equals(appId)){
			return JSONMessage.failureByErrCode(PayResultCode.AppIdWrong);
		}
		order.setUserId(userId.toString());
		order.setStatus((byte)1);
		saveEntity(order);
		
		// 创建消费记录
		String lessTradeNo=StringUtil.getOutTradeNo();
		ConsumeRecord consumeRecord = new ConsumeRecord();
		consumeRecord.setMoney(Double.valueOf(order.getMoney()));
		consumeRecord.setOrderId(order.getId());
		// 消费记录type需要修改
		consumeRecord.setType(14);
		consumeRecord.setPayType(3);
		consumeRecord.setDesc(order.getDesc());
		consumeRecord.setTime(DateUtil.currentTimeSeconds());
		consumeRecord.setStatus(KConstants.OrderStatus.END);
		consumeRecord.setTradeNo(lessTradeNo);
		consumeRecord.setUserId(userId);
		SKBeanUtils.getConsumeRecordManager().save(consumeRecord);
		
		// 减钱
		SKBeanUtils.getUserManager().rechargeUserMoeny(userId, Double.valueOf(order.getMoney()), KConstants.MOENY_REDUCE);
		
		User sysUser=SKBeanUtils.getUserManager().get(1100);
		SkOpenApp openApp = SKBeanUtils.getOpenAppManage().getOpenAppByAppId(appId);
		JSONObject obj = new JSONObject();
		obj.put("orderId", order.getId().toString());
		obj.put("money", order.getMoney());
		obj.put("icon", openApp.getAppImg());
		obj.put("name", openApp.getAppName());
		MessageBean message=new MessageBean();
		message.setFromUserId(sysUser.getUserId().toString());
		message.setFromUserName(sysUser.getNickname());
		message.setType(KXMPPServiceImpl.OPENPAYSUCCESS);
		message.setMsgType(0);
		message.setMessageId(StringUtil.randomUUID());
		message.setContent(obj);
		message.setToUserId(user.getUserId().toString());
		message.setToUserName(user.getNickname());
		try {
			KXMPPServiceImpl.getInstance().send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		// 异步回调通知路径
		ThreadUtils.executeInThread(new PaySyncCallbackEx(order),1);
		return JSONMessage.success();
	}
	/**
	 * 确认密码支付
	 * @param appId
	 * @param prepayId
	 * @param sign
	 * @param userId
	 * @return
	 */
	public JSONMessage passwordPaymentV1(String appId,String prepayId,String sign,Integer userId){

		User user = SKBeanUtils.getUserManager().get(userId);
		if(!SKBeanUtils.getRedisService().queryPayOrderSign(prepayId).equals(sign)){
			return JSONMessage.failureByErrCode(PayResultCode.AuthSignFailed);
		}

		Query<PayOrder> query = getDatastore().createQuery(PayOrder.class).field("_id").equal(new ObjectId(prepayId));
		if(null==query.get()){
			return JSONMessage.failureByErrCode(PayResultCode.OrderNotExist);
		}

		PayOrder order = query.get();
		if(Double.valueOf(order.getMoney())<0){
			throw new ServiceException(PayResultCode.InsufficientBalance);
		}
		if(!order.getAppId().equals(appId)){
			return JSONMessage.failureByErrCode(PayResultCode.AppIdWrong);
		}
		order.setUserId(userId.toString());
		order.setStatus((byte)1);
		saveEntity(order);

		// 创建消费记录
		String lessTradeNo=StringUtil.getOutTradeNo();
		ConsumeRecord consumeRecord = new ConsumeRecord();
		consumeRecord.setMoney(Double.valueOf(order.getMoney()));
		consumeRecord.setOrderId(order.getId());
		// 消费记录type需要修改
		consumeRecord.setType(14);
		consumeRecord.setPayType(3);
		consumeRecord.setDesc(order.getDesc());
		consumeRecord.setTime(DateUtil.currentTimeSeconds());
		consumeRecord.setStatus(KConstants.OrderStatus.END);
		consumeRecord.setTradeNo(lessTradeNo);
		consumeRecord.setUserId(userId);
		SKBeanUtils.getConsumeRecordManager().save(consumeRecord);

		// 减钱
		SKBeanUtils.getUserManager().rechargeUserMoeny(userId, Double.valueOf(order.getMoney()), KConstants.MOENY_REDUCE);

		User sysUser=SKBeanUtils.getUserManager().get(1100);
		SkOpenApp openApp = SKBeanUtils.getOpenAppManage().getOpenAppByAppId(appId);
		JSONObject obj = new JSONObject();
		obj.put("orderId", order.getId().toString());
		obj.put("money", order.getMoney());
		obj.put("icon", openApp.getAppImg());
		obj.put("name", openApp.getAppName());
		MessageBean message=new MessageBean();
		message.setFromUserId(sysUser.getUserId().toString());
		message.setFromUserName(sysUser.getNickname());
		message.setType(KXMPPServiceImpl.OPENPAYSUCCESS);
		message.setMsgType(0);
		message.setMessageId(StringUtil.randomUUID());
		message.setContent(obj);
		message.setToUserId(user.getUserId().toString());
		message.setToUserName(user.getNickname());
		try {
			KXMPPServiceImpl.getInstance().send(message);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//保存需要回调到缓存

		// 异步回调通知路径
	//	ThreadUtils.executeTimerTask(new PaySyncCallback(order),5,30);
		ThreadUtils.executeInThread(new PaySyncCallbackEx(order),1);
		return JSONMessage.success();
	}

	
	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 */
	public String createSign(SortedMap<String, String> packageParams,String szSecretKey) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + szSecretKey);
		//System.out.println("key====="+this.getKey());
		String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8")
				.toUpperCase();

		logger.info("[ww]sign="+sign+",sb.toString()="+sb.toString());
		return sign;

	}

    public double queryCodePayCount(int userId){
        DBObject groupFileds =new BasicDBObject();
        groupFileds.put("userId", "$userId");
        // 过滤条件
        BasicDBObject query =new BasicDBObject();
        query.put("userId", userId);
        DBObject macth=new BasicDBObject("$match",query);

        DBObject fileds = new BasicDBObject("_id", groupFileds);
        fileds.put("count", new BasicDBObject("$sum","$money"));
        DBObject group = new BasicDBObject("$group", fileds);
        DBCollection collection = getDatastore().getCollection(CodePay.class);
        AggregationOutput out= collection.aggregate(Arrays.asList(macth,group));
        Iterator<DBObject> result=out.results().iterator();
        while (result.hasNext()){
            return  Double.valueOf(result.next().get("count").toString());
        }
       return 0;
    }
	public double queryToDayCodePayCount(int userId){
		DBObject groupFileds =new BasicDBObject();
		groupFileds.put("userId", "$userId");
		// 过滤条件
		BasicDBObject query =new BasicDBObject();
		query.put("userId", userId);
		query.put("createTime",
				new BasicDBObject(MongoOperator.GT,DateUtil.getTodayMorning().getTime()/1000)
						.append(MongoOperator.LTE,DateUtil.currentTimeSeconds()));

		DBObject macth=new BasicDBObject("$match",query);

		DBObject fileds = new BasicDBObject("_id", groupFileds);
		fileds.put("count", new BasicDBObject("$sum","$money"));
		DBObject group = new BasicDBObject("$group", fileds);
		DBCollection collection = getDatastore().getCollection(CodePay.class);
		AggregationOutput out= collection.aggregate(Arrays.asList(macth,group));
		Iterator<DBObject> result=out.results().iterator();
		while (result.hasNext()){
			return  Double.valueOf(result.next().get("count").toString());
		}
		return 0;
	}
	private  class  PaySyncCallbackEx implements Callback {
		private PayOrder order;
		private int errCount = 0;
		public  PaySyncCallbackEx(PayOrder order)
		{
			this.order=order;
			this.errCount = 0;
		}
		@Override
		public void execute(Object obj) {
			String callBackUrl = order.getCallBackUrl();
			if(StringUtil.isEmpty(callBackUrl)) {
				if(order.getAppType().equals("APP")){
					Query<SkOpenApp> openAppQuery=getDatastore().createQuery(SkOpenApp.class).field("appId").equal(order.getAppId());
					callBackUrl = openAppQuery.get().getPayCallBackUrl();
				}else{
					Query<SkOpenApp> openWebQuery = getDatastore().createQuery(SkOpenApp.class).field("appId").equal(order.getAppId());
					callBackUrl = openWebQuery.get().getPayCallBackUrl();
				}
			}
			try {
				SortedMap<String, String> contentMap = new TreeMap<String, String>();
				contentMap.put("out_trade_no", order.getTrade_no());
				String jsonParms = JSONObject.toJSONString(contentMap);

				logger.info("第三方支付成功,开始回调,callBackUrl="+callBackUrl+",postJson="+JSONObject.parseObject(jsonParms));
				String szOk = HttpClientUtil.sendJsonMessage(callBackUrl,JSONObject.parseObject(jsonParms));
				if(szOk == null) szOk = "";
				logger.info("第三方支付成功,回调结果,responseCode="+szOk);
				if(szOk.equals("ok")){
					logger.info("支付回调成功");

				}else{
					logger.info("支付回调失败继续尝试请求");
					if(errCount < 5)
					{
						this.errCount++;
						ThreadUtils.executeInThread(this,30);
					}

				}
			}catch (Exception e) {
				if(errCount < 5)
				{
					this.errCount++;
					ThreadUtils.executeInThread(this,30);
				}
				e.printStackTrace();
			}
		}
	}

}
